Skip to content

build: replace django-pglocks with django-pgware - #728

Open
blaipr wants to merge 1 commit into
ctrliq:mainfrom
blaipr:build/bump-django-pglocks-2.1.0-requirements
Open

build: replace django-pglocks with django-pgware#728
blaipr wants to merge 1 commit into
ctrliq:mainfrom
blaipr:build/bump-django-pglocks-2.1.0-requirements

Conversation

@blaipr

@blaipr blaipr commented Aug 23, 2026

Copy link
Copy Markdown
Contributor
SUMMARY

Replaces django-pglocks with django-pgware, which provides the advisory locks awx/main/utils/pglock.py wraps and the task manager and dispatcher take to serialise work across nodes.

This started as a bump of django-pglocks from 1.0.4 to 2.1.0. @cigamit pointed out that 2.1.0 is a shim, and it is: the whole package is a DeprecationWarning and a re-export.

warnings.warn(
    "django-pglocks has been consolidated into django-pgware. "
    "Install django-pgware (it imports as django_pg_utils) and update "
    "imports to django_pg_utils.locks. "
    "This compatibility package will not receive further updates.",
    DeprecationWarning,
    stacklevel=2,
)

from django_pg_utils.locks import advisory_lock, async_advisory_lock

So the dependency moves to django-pgware and the one import site moves with it. Taking the shim would have pulled in django-pgware anyway, as the original diff here showed, plus a deprecation warning on every import.

What changed:

  • requirements.in and requirements.txt: django-pglocks out, django-pgware==1.0.0 in as a direct requirement rather than something pulled in behind the shim.
  • awx/main/utils/pglock.py: from django_pglocks import advisory_lock becomes from django_pg_utils.locks import advisory_lock. This is the only import site in the tree; the other fourteen call sites go through this wrapper.
  • licenses/: django-pglocks.txt out, django-pgware.txt in, or test_licenses.py::test_python_and_js_licenses fails on both halves.
  • six loses a consumer but stays, for isodate, kubernetes, openshift, pygerduty and pyrad. django-pgware needs nothing but Django.

shared, wait, comment and using are keyword only in django-pgware. Every call site in the tree passes the lock name positionally and wait by keyword, so all fourteen are already in the accepted form.

One thing to know before merging

The lock id derived from a string lock name changed, and this is true of the 2.1.0 shim as well, since the shim delegates the hashing:

lock name 1.0.4, crc32 django-pgware, sha256
cluster_policy_lock -1098137126 -8960390604963387910
awx_periodic_scheduler_lock -756382330 2829273023766493690
gather_analytics_lock 706743891 8443325817634918083

A node on the old release and a node on the new one therefore do not exclude each other on the same lock name, for as long as a rolling upgrade has both running. It clears once every node is on the same release. Worth a line in the release notes rather than a change here, since there is no version of this move that keeps the old ids.

ISSUE TYPE
  • Bug, Docs Fix or other nominal change
COMPONENT NAME
  • API
ASCENDER VERSION
25.5.1

Tests

On a real PostgreSQL, because nothing else exercises it. awx/main/utils/pglock.py short circuits to yield True whenever connection.vendor is not postgresql, so a green SQLite suite says nothing about this library. The wrapper, with the new import, against the running database:

vendor: postgresql
blocking acquire -> True
try acquire (free) -> True
formatted name -> True
advisory locks still held: 0        # released on exit

And the property the callers depend on, across two connections:

conn A blocking acquire -> True
conn B try acquire while held -> False
conn B try acquire after release -> True

Same result as 1.0.4, so the semantics AWX relies on are unchanged.

The rest of the suite, on a freshly created database:

py.test --create-db -n auto --dist=loadfile \
  awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests

  1 failed, 3816 passed, 10 skipped in 8m42s
  FAILED awx/main/tests/functional/api/test_generic.py::test_proxy_ip_allowed

That failure is not this change. test_proxy_ip_allowed patches REMOTE_HOST_HEADERS and PROXY_IP_ALLOWED_LIST on the settings singleton and intermittently sees another worker's state under -n auto; it passes solo, and it is the flake instrumented in #694.

Rebased onto current main, which drops the licenses/docutils.txt failure the earlier run here hit.

@cigamit cigamit self-assigned this Aug 26, 2026
@cigamit cigamit added dependencies Pull requests that update a dependency file python Pull requests that update python code Needs triage When a Issue needs to be researched or a PR has an issue that needs fixing before merging labels Aug 26, 2026
@blaipr
blaipr force-pushed the build/bump-django-pglocks-2.1.0-requirements branch from a56a565 to f07c019 Compare August 26, 2026 11:50
@blaipr

blaipr commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main to clear the conflict. It was only positional: django-polymorphic moved to 4.11.7 in #722 on the line right after the new django-pgware entry.

The change itself is unchanged: django-pglocks 1.0.4 to 2.1.0, the new django-pgware==1.0.0 it pulls in, six losing it as a consumer, and licenses/django-pgware.txt.

@cigamit

cigamit commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

This package is deprecated and the newest version you are upgrading to is just a shim for the new django-pgware package you imported. So its best just to move to the new one.

https://github.com/Xof/django-pglocks
https://github.com/Xof/django-pglocks/releases/tag/v2.1.0
https://github.com/Xof/django-pgware

django-pglocks 2.1.0 is a deprecation shim: it warns on import and
re-exports advisory_lock from django_pg_utils.locks, which is what
django-pgware installs. Depending on it buys a DeprecationWarning on every
import and nothing else, so take the dependency it forwards to instead.

awx/main/utils/pglock.py is the only import site in the tree; every caller
goes through the wrapper there, and all of them pass the lock name
positionally and wait= by keyword, which is what django-pgware accepts now
that shared, wait, comment and using are keyword only.

django-pglocks also pulled in six, which stays for isodate, kubernetes,
openshift, pygerduty and pyrad. django-pgware needs nothing but Django.

Note for upgrades: the string lock name is hashed to a lock id differently,
crc32 folded to 32 bits before and sha256 truncated to 64 bits now, so a
node on the old code and a node on the new one do not exclude each other on
the same lock name. That is true of the 2.1.0 shim as well, since the shim
delegates the hashing, and it clears once every node runs the same release.
@blaipr
blaipr force-pushed the build/bump-django-pglocks-2.1.0-requirements branch from f07c019 to e351674 Compare August 30, 2026 13:41
@blaipr blaipr changed the title build: bump django-pglocks from 1.0.4 to 2.1.0 in /requirements build: replace django-pglocks with django-pgware Aug 30, 2026
@blaipr

blaipr commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

You are right, and it is worse than a shim in spirit: the whole package is a warning and two re-exported names.

warnings.warn(
    "django-pglocks has been consolidated into django-pgware. "
    "Install django-pgware (it imports as django_pg_utils) and update "
    "imports to django_pg_utils.locks. "
    "This compatibility package will not receive further updates.",
    DeprecationWarning,
    stacklevel=2,
)

from django_pg_utils.locks import advisory_lock, async_advisory_lock

So the shim is gone and this is now the move to django-pgware. Retitled and the body rewritten to match.

The import. awx/main/utils/pglock.py is the only import site in the tree, and the other fourteen call sites go through the wrapper there:

-from django_pglocks import advisory_lock as django_pglocks_advisory_lock
+from django_pg_utils.locks import advisory_lock as pgware_advisory_lock

shared, wait, comment and using are keyword only now. All fourteen call sites pass the lock name positionally and wait by keyword, so none of them had to change.

licenses/django-pglocks.txt is out and licenses/django-pgware.txt in, which test_python_and_js_licenses checks both ways. six loses a consumer but stays for isodate, kubernetes, openshift, pygerduty and pyrad; django-pgware needs nothing but Django.

One thing worth knowing before this merges. The lock id derived from a string name changed, and it changed in the shim too, since the shim delegates the hashing. 1.0.4 used crc32 folded to 32 bits, django-pgware uses sha256 truncated to 64:

lock name 1.0.4 django-pgware
cluster_policy_lock -1098137126 -8960390604963387910
awx_periodic_scheduler_lock -756382330 2829273023766493690
gather_analytics_lock 706743891 8443325817634918083

So during a rolling upgrade a node on the old release and a node on the new one do not exclude each other on the same lock name. It clears once every node is on the same release, and there is no version of this move that keeps the old ids, so I have left it as a release note rather than trying to solve it here. Say the word if you would rather it were called out somewhere in the tree.

Verified against the running PostgreSQL rather than the SQLite suite, since the wrapper short circuits to yield True for any other vendor:

conn A blocking acquire -> True
conn B try acquire while held -> False
conn B try acquire after release -> True

Same as 1.0.4. Rebased onto current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file Needs triage When a Issue needs to be researched or a PR has an issue that needs fixing before merging python Pull requests that update python code

Development

Successfully merging this pull request may close these issues.

2 participants